import numbers
import os
import random
import subprocess
from typing import Type

from OpenSSL import crypto
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization


class Sovereign:
    city_name = ''
    organization_name = ''
    department_name = ''
    province_name = ''
    country_name = ''
    common_name = 'unknown'
    encryption_algorithm = 'RSA'
    hash = 'SHA256'
    bit_num = 'prime256v1'

    def __init__(self, country, province, city, organization, department, common_name='unknown'):
        self.country_name = country
        self.province_name = province
        self.city_name = city
        self.organization_name = organization
        self.department_name = department
        self.common_name = common_name


'''
证书签名
'''


def ca_sign(csr_file_path: str, out_path: str, valid_days: int = 90):
    print(valid_days)
    with open(csr_file_path, "rb") as csr_file:
        csr_data = csr_file.read()
    csr = crypto.load_certificate_request(crypto.FILETYPE_PEM, csr_data)
    Sovereign.organization_name = "QUNZHE"
    Sovereign.department_name = "DEVELOPMENT"
    Sovereign.city_name = "KUNMING"
    Sovereign.province_name = "YUNNAN"
    Sovereign.country_name = "CN"
    Sovereign.common_name = 'unknown'
    Sovereign.encryption_algorithm = "RSA"
    Sovereign.hash = "SHA256"
    Sovereign.bit_num = "prime256v1"
    self_sign = cert_sign(Sovereign, valid_days, subject=csr.get_subject())
    with open(out_path + '/CA_private.pem', "wb") as f:
        f.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, self_sign.private_key))

    # 保存证书到文件
    with open(out_path + '/CA_certificate.cer', "wb") as f:
        f.write(crypto.dump_certificate(crypto.FILETYPE_PEM, self_sign.cert))


def get_ca_private_key(key_file):
    with open(key_file, 'r', encoding='utf-8') as file:
        content = file.read()
    return content

def get_ca_public_key(path_file):
    with open(path_file, "rb") as key_file:
        private_key = serialization.load_pem_private_key(
            key_file.read(),
            password=None,  # 如果私钥是加密的，这里需要提供密码
            backend=default_backend()
        )
    public_key = private_key.public_key().public_bytes(
        encoding=serialization.Encoding.PEM,
        format=serialization.PublicFormat.SubjectPublicKeyInfo)
    return public_key.decode("utf-8")

'''
生成私钥
'''


def private_key_factory(length=2048):
    key = crypto.PKey()
    key.generate_key(crypto.TYPE_RSA, length)
    return key


class SelfSign:
    cert: crypto.X509 = {},
    private_key: crypto.PKey = ''


def csr_sign(sovereign: Type[Sovereign], out: str):
    private_key = private_key_factory()
    req = crypto.X509Req()  # CSR证书使用X509Req
    req.get_subject().C = sovereign.country_name
    req.get_subject().ST = sovereign.city_name
    req.get_subject().L = sovereign.province_name
    req.get_subject().O = sovereign.organization_name
    req.get_subject().OU = sovereign.department_name
    req.get_subject().CN = sovereign.common_name
    req.set_pubkey(private_key)
    req.sign(private_key, sovereign.hash.lower())
    with open(out + "/private_key.pem", "wb") as f:
        f.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, private_key))

    with open(out + "/certificate.csr", "wb") as f:
        f.write(crypto.dump_certificate_request(crypto.FILETYPE_PEM, req))


'''
证书签名
'''


def cert_sign(sovereign: Type[Sovereign], valid_days: int, subject=None):
    private_key = private_key_factory()
    cert = crypto.X509()
    cert.get_issuer().C = sovereign.country_name
    cert.get_issuer().ST = sovereign.city_name
    cert.get_issuer().L = sovereign.province_name
    cert.get_issuer().O = sovereign.organization_name
    cert.get_issuer().OU = sovereign.department_name
    cert.get_issuer().CN = sovereign.common_name
    cert.set_serial_number(random_with_len(10000, 99999))  # 序列号
    cert.gmtime_adj_notBefore(0)  # 有效期开始时间
    cert.gmtime_adj_notAfter(valid_days * 24 * 60 * 60)
    if subject:
        cert.set_subject(subject)
    else:
        cert.set_subject(cert.get_issuer())

    cert.set_pubkey(private_key)
    cert.sign(private_key, sovereign.hash.lower())
    SelfSign.cert = cert
    SelfSign.private_key = private_key
    return SelfSign


'''
随机数
'''


def random_with_len(mn: numbers, mm: numbers):
    return random.randint(mn, mm)


def p12_factory(certificate_path, private_key, password, out):
    openssl_command = f'openssl pkcs12 -export -out {out}/certificate.p12 -inkey {private_key} -in {certificate_path} -passout pass:{password}'
    try:
        subprocess.run(openssl_command, check=True)
    except subprocess.CalledProcessError as e:
        print(e)

